package com.yc.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yc.common.utils.AlyExcelUtil;
import com.yc.common.utils.CustomCellWriteHeightConfig;
import com.yc.common.utils.CustomCellWriteWeightConfig;
import com.yc.entity.*;
import com.yc.exception.CustomException;
import com.yc.mapper.*;
import com.yc.service.AttendanceRecordsService;
import com.yc.service.AttendanceService;
import com.yc.service.impl.ScheduleServiceImpl;
import com.yc.vo.AttendanceHistory;
import com.yc.vo.Result;
import com.yc.vo.ScheduleDetail;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author zhupanlin
 * @version 1.0
 * @description: TODO
 * @date 2023/7/20 11:37
 */
@Api("学生考勤控制器")
@RestController
@RequestMapping("/attendance")
public class AttendanceController {
    @Resource
    private ClassInfoMapper classInfoMapper;
    @Resource
    private StudentInfoMapper studentInfoMapper;
    @Resource
    private ScheduleMapper scheduleMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private AttendanceService attendanceService;
    @Resource
    private AttendanceRecordsMapper attendanceRecordsMapper;
    @Resource
    private AttendanceMapper attendanceMapper;
    @Resource
    private AttendanceRecordsService attendanceRecordsService;

    @Resource
    private ScheduleServiceImpl scheduleService;

    @Resource
    private RedisTemplate redisTemplate;

    @ApiOperation("查询当前老师上课班级的学生")
    @GetMapping("/get/{username}")
    public Result selectStudentBySchedule(@ApiParam(name = "username", value = "上课老师的工号", required = true)
                                          @PathVariable("username") String username) {
        return Result.success(attendanceService.selectStudentByAttId(username));
    }

    @ApiOperation("查询当前这节课是否有考勤记录")
    @GetMapping("/getAttId/{username}")
    public Result selectAttId(@ApiParam(name = "username", value = "上课老师的工号", required = true)
                              @PathVariable("username") String username,
                              @RequestParam("classId") String classId) {
        Schedule schedule = scheduleService.selectScheduleByCidAndDate(username, classId);
        // 插入之前查询是否有记录
        Integer attId = attendanceService.selectAttendanceByScheduleId(schedule.getId() + "");
        return Result.success(attId);
    }

    @ApiOperation("手动添加考勤信息")
    @PostMapping("/add/{username}")
    public Result addAttendance(@ApiParam(name = "username", value = "上课老师的工号", required = true)
                                @PathVariable("username") String username,
                                @RequestParam("classId") String classId,
                                @RequestParam("arrivecount") Integer arrivecount,
                                @RequestParam("signmethod") Integer signmethod,
                                @RequestParam(value = "uuid", required = false) String uuid) {
        Attendance attendance = new Attendance();
        attendance.setClassId(classId);
        attendance.setArrivedcount(arrivecount);
        attendance.setCreateBy(username);
        attendance.setUpdateBy(username);
        attendance.setSignmethod(signmethod);
        Schedule schedule = scheduleService.selectScheduleByCidAndDate(username, classId);
        attendance.setScheduleid(schedule.getId());
        // 插入之前查询是否有记录
        Integer attId = attendanceService.selectAttendanceByScheduleId(schedule.getId() + "");
        attendance.setId(attId);
        Result result;
        // 有记录 则 修改 没有 就新增
        if (attId == null || attId <= 0) {
            attendanceService.addAttendance(attendance);
            result = new Result(1, attendance.getId());
            result.setMsg("添加成功!");
        } else {
            // 修改
            attendanceService.modifyAttendance(attendance);
            result = new Result(1, attId);
            result.setMsg("修改成功!");
        }
        // 通过uuid释放资源
        if (uuid != null) {
            // 释放redis中的学生资源
            redisTemplate.delete(uuid);
            // 释放连接
            QrCodeEndpoint.onlineQrCode.remove(uuid);
            // 释放时间戳
            QrCodeController.SAVE_TIMESTAMP.remove(uuid);
        }

        return result;
    }


    /**
     * 分页查询
     *
     * @param scheduleDetail 筛选的课表条件
     * @return 查询结果
     */
    @ApiOperation("分页查询")
    @GetMapping
    public Result paginQuery(ScheduleDetail scheduleDetail,
                             @RequestParam(required = false, defaultValue = "1") Integer pageNum,
                             @RequestParam(required = false, defaultValue = "10") Integer pageSize,
                             HttpServletRequest request) {
        //先判别身份
        User user = (User) request.getSession().getAttribute("user");
        User user1 = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getId, user.getId()));
        List<Long> roles = user1.getRole();

        //数据
        List<ScheduleDetail> scheduleDetails = null;
        //数据总数
        int count = 0;
        //1.分页参数
        long current = (long) (pageNum - 1) * pageSize;
        long size = pageSize;

        scheduleDetails = roles.contains(1) ?
                attendanceMapper.selectPage(scheduleDetail, current, size, null) :
                attendanceMapper.selectPage(scheduleDetail, current, size, user1.getId());
        //遍历给其中的记录的属性status赋值
        scheduleDetails.forEach(s -> {
            s.setStatus(scheduleDetail.getStatus());
        });

        count = roles.contains(1) ?
                attendanceMapper.count(scheduleDetail, current, size, null) :
                attendanceMapper.count(scheduleDetail, current, size, user1.getId());

        Map<Integer, String> weekMap= new HashMap<>();
        weekMap.put(1,"星期天");
        weekMap.put(2,"星期一");
        weekMap.put(3,"星期二");
        weekMap.put(4,"星期三");
        weekMap.put(5,"星期四");
        weekMap.put(6,"星期五");
        weekMap.put(7,"星期六");

        if(scheduleDetails!=null && !scheduleDetails.isEmpty()){
            scheduleDetails.stream().forEach(item->{
                item.setWeekStr(weekMap.get(item.getIsweek()));
            });
        }

        Map<String, Object> data = new HashMap<>();
        data.put("list", scheduleDetails);
        data.put("total", count);
        return Result.success(data);
    }

    /**
     * @Description 查询所有的课程名
     * @Return
     * @Author dm
     * @Date Created in 2023/7/11 11:17
     **/
    @ApiOperation("查询所有课程信息")
    @GetMapping("/courses")
    public Result getCourses(String teacherId) {
        //查询身份
        boolean isTeacher = userMapper.selectById(teacherId).getRole().contains(3);
        List<String> courses = null;
        if (isTeacher) {
            courses = scheduleMapper.queryCourses(teacherId);
        } else {
            courses = scheduleMapper.queryCourses(null);
        }

        if (courses != null) {
            return Result.success(courses);
        } else {
            return Result.error("初始化失败");
        }
    }

    /**
     * @Description 生成考勤表中的内容
     * @Return
     * @Author dm
     * @Date Created in 2023/7/12 15:28
     **/

    @ApiOperation("生成考勤表中的相关信息")
    @GetMapping("/exportContent")
    public void exportContent(String excels, HttpServletResponse response) throws IOException {
        // 设置响应头，影响浏览器下载行为,下面繁琐的代码的目的是为了适应网页那端能够展示出用户保存考勤表到指定位置的框所需要改变的
        //发送的get请求
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        // 使用URLEncoder对文件名进行编码，避免中文乱码
        String fileName = URLEncoder.encode("考勤表_" + date, String.valueOf(StandardCharsets.UTF_8)) + ".xlsx";
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        String[] strings = excels.substring(1, excels.length() - 1).split(",");
        ServletOutputStream out = null;
        try {
            //追加内容难以实现插入多个头部，后面的头部会覆盖前面的，所以采用多个sheet的方法实现多个考勤表的导出
            // 文件输出位置
            out = response.getOutputStream();

            // 指定文件，自定义列宽，注册样式
            ExcelWriter excelWriter = EasyExcel.write(out)
                    .registerWriteHandler(new CustomCellWriteWeightConfig())
                    .registerWriteHandler(new CustomCellWriteHeightConfig()).build();
            //sheet个数
            int sheet = 1;
            int i = 1;
            for (String string : strings) {
                int index = Integer.parseInt(string);
                //查出课表信息
                Schedule schedule = scheduleMapper.selectById(index);
                String classId = schedule.getClassid();
                //是否是多个班级一起上课
                Map<String, List<StudentInfo>> classes = new HashMap<>();

                ScheduleDetail scheduleDetail = new ScheduleDetail();
                //课程名称
                scheduleDetail.setCoursename(schedule.getCoursename());
                //先将班级学生全部查出来
                List<StudentInfo> studentInfos = studentInfoMapper.queryAllByClassId(classId);

                //一个或多个班级的集合
                classes.put(classId, studentInfos);

                //班级名称
                scheduleDetail.setCname(classInfoMapper.selectById(classId).getCname());
                //考勤教师
                scheduleDetail.setNickname(userMapper.selectById(schedule.getTeacherid()).getNickname());
                //教室
                scheduleDetail.setClassroom(schedule.getClassroom());
                //课表id
                scheduleDetail.setCid(index);
                // 动态添加表头
                WriteSheet sheet1 = new WriteSheet();
                //每个sheet的名字
                sheet1.setSheetNo(sheet++);
                sheet1.setSheetName("第" + schedule.getWeek() + "周第" + schedule.getClasstime() + "节_sheet" + i++);

                // 创建一个表格，用于 Sheet 中使用
                WriteTable table = new WriteTable();
                table.setTableNo(1);
                table.setHead(AlyExcelUtil.head(scheduleDetail));
                // 写数据
                excelWriter.write(AlyExcelUtil.contentData(classes), sheet1, table);
            }
            //这一步很关键，不然文件会损坏
            excelWriter.finish();
        } catch (IOException e) {
            e.printStackTrace();
            throw new CustomException("0", "系统异常");
        }
    }


    /**
     * @Description 上传考勤表中的信息
     * @Return
     * @Author dm
     * @Date Created in 2023/7/15 9:17
     **/
    @ApiOperation("上传已经编辑好的excel信息表格")
    @PostMapping("/upload")
    public Result upload(MultipartFile file, String notes, HttpServletRequest request) throws IOException {
        InputStream inputStream = file.getInputStream();
        User user = (User) request.getSession().getAttribute("user");
        int upload = attendanceService.upload(inputStream, notes, user.getId() + "");
        if (upload == 0) {
            return Result.success("上传文件成功");
        } else if (upload > 0) {
            return Result.error("上传的文件数据第" + upload + "行有未识别的字符");
        } else {
            return Result.error("系统异常");
        }
    }

    /**
     * @Description 查询班级的历史考勤信息
     * @Return
     * @Author dm
     * @Date Created in 2023/7/21 14:57
     **/
    @ApiOperation("查询班级的历史考勤信息")
    @GetMapping("/searchHistory")
    public Result queryHistory(AttendanceHistory attendanceHistory,
                               @RequestParam(required = false, defaultValue = "1") Integer pageNum,
                               @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
        return attendanceRecordsService.queryHistory(attendanceHistory, pageNum, pageSize);
    }

    /**
     * @Description 修改考勤状态
     * @Return
     * @Author dm
     * @Date Created in 2023/7/22 16:26
     **/
    @ApiOperation("修改个别同学的考勤状态")
    @GetMapping("/updateStatus")
    public boolean updateStatus(String arid, String status) {
        status = status.split(" ")[0];
        switch (status) {
            case "已到":
                status = "1";
                break;
            case "请假":
                status = "2";
                break;
            case "迟到":
                status = "3";
                break;
            case "早退":
                status = "4";
                break;
            case "旷课":
                status = "5";
                break;
        }
        int i = attendanceRecordsMapper.updateById(arid, status);
        return i > 0;
    }

    /**
     * @Description 快速考勤所需要的数据接口
     * @Return
     * @Author dm
     * @Date Created in 2023/8/7 18:41
     **/
    @ApiOperation("修改个别同学的考勤状态")
    @GetMapping("/fastFunction")
    public Result fastFunction(String tid) {
        String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        List<Attendance> attendances = attendanceMapper.queryFastData(tid, "2023-09-05 09:20:00");
        //根据其中的班级id查询得出其中的总人数以及请假人数
        Map<String, List<Integer>> map = new HashMap<>();
        attendances.forEach(attendance -> {
            //查询请假人数
            //先格式化其中的日期再做查询
            Integer leaveNums = attendanceMapper.queryLeaveNums(attendance.getClassId(),
                    attendance.getBegin(), attendance.getEnd());
            //数组中存储的依次是总人数，请假人数，以及应该到达的人数
            List<Integer> nums = new ArrayList<>();
            nums.add(attendance.getTotal());
            nums.add(leaveNums);
            nums.add(attendance.getTotal() - leaveNums);
            map.put(attendance.getCname(), nums);
        });
        return Result.success(map);
    }
}
